// 工厂模式
; (function () {
    return
    function createPerson(name) {
        var o = new Object();
        o.name = name;
        o.getName = function () {
            console.log(this.name);
        };

        return o;
    }

    var person1 = createPerson('kevin');
    var person2 = createPerson('nihao');
    console.log(person1.__proto__ === person2.__proto__) // true

    //对象无法识别，因为所有的实例都指向一个原型
})();

// 构造函数模式
; (function () {
    return
    //   版本1
    function Person(name) {
        this.name = name;
        this.getName = function () {
            console.log(this.name);
        };
    }

    var person1 = new Person('kevin');
    var person2 = new Person('su');
    // 优点：实例可以识别为一个特定的类型
    // 缺点：每次创建实例时，每个方法都要被创建一次


    //  版本2
    function Person2(name) {
        this.name = name;
        this.getName = getName;
    }
    function getName() {
        console.log(this.name);
    }
    var person21 = new Person2('kevin');
    var person22 = new Person2('sun');

    // 优点：解决了每个方法都要被重新创建的问题

    // 缺点：这叫啥封装……

})();

//原型模式
; (function () {
    //return

    // 版本1=================================
    function Person(name) { }

    Person.prototype.name = 'keivn';
    Person.prototype.getName = function () {
        console.log(this.name);
    };
    // 优点：方法不会重新创建
    // 缺点：1. 所有的属性和方法都共享 2. 不能初始化参数

    // 版本2=================================

    function Person(name) { }

    Person.prototype = {
        name: 'kevin',
        getName: function () {
            console.log(this.name);
        }
    };
    // 缺点：重写了原型，丢失了constructor属性

    // 版本三=================================

    function Person(name) {

    }

    Person.prototype = {
        constructor: Person, // constructor属性有了
        name: 'kevin',
        getName: function () {
            console.log(this.name);
        }
    };


    // 缺点：原型模式该有的缺点还是有

})();

// 组合模式 用途最广泛
; (function () {
    //return
    function Person(name) {
        this.name = name;
    }

    Person.prototype = {
        constructor: Person,
        getName: function () {
            console.log(this.name);
        }
    };

    var person1 = new Person();

    // 优点：该共享的共享，该私有的私有，使用最广泛的方式

    // 缺点：有的人就是希望全部都写在一起，即更好的封装性

})();

//动态原型模式
; (function () {
    //return
    function Person(name) {
        this.name = name;
        if (typeof this.getName != "function") {
            Person.prototype.getName = function () {
                console.log(this.name);
            }
        }
    }

    var person1 = new Person("你好");
    person1.getName()// 你好

    // 注意点 字面量模式=================================
    function Person(name) {
        this.name = name;
        // 简单解释,就是在执行Person之前,
        // (实例).__proto__ = Person.prototype
        if (typeof this.getName != "function") {
            //Person.prototype 改变了指向
            //(实例).__proto__没有改变
            Person.prototype = {
                constructor: Person,
                getName: function () {
                    console.log(this.name);
                }
            }
        }
    }
    // 修改=================================
    function Person(name) {
        this.name = name;
        if (typeof this.getName != "function") {
            Person.prototype = {
                constructor: Person,
                getName: function () {
                    console.log(this.name);
                }
            }
            // 其实相当于递归调用
            return new Person(name);
        }
    }

    var person1 = new Person('kevin');
    var person2 = new Person('daisy');

    person1.getName(); // kevin
    person2.getName();  // daisy
    // =================================    




})();


// 寄生构造函数模式 (没什么用 不想写)
// 稳妥构造函数模式
; (function () {
    //return
    function person(name) {
        var o = new Object();
        o.sayName = function () {
            console.log(name);
        };
        return o;
    }

    var person1 = person('kevin');

    person1.sayName(); // kevin

    person1.name = "daisy";

    person1.sayName(); // kevin // 没有改变是因为,用的是那个函数创建时的形参

    console.log(person1.name); // daisy

    // 新创建的实例方法不引用 this
    // 不使用 new 操作符调用构造函数
    // 稳妥对象最适合在一些安全的环境中。

    // 稳妥构造函数模式也跟工厂模式一样，无法识别对象所属类型。

})();